package fiuba.td.fabrica.model.utils;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import org.apache.log4j.Logger;

import fiuba.td.fabrica.model.entities.CintaTransportadora;
import fiuba.td.fabrica.model.entities.Producto;
import fiuba.td.fabrica.model.exceptions.ConexionCintaTransportadoraOcupadaException;
import fiuba.td.fabrica.model.exceptions.ConexionConectableOcupadoException;
import fiuba.td.fabrica.model.exceptions.TipoMaquinaInvalidoException;
import fiuba.td.fabrica.model.factories.MaquinaFactory;
import fiuba.td.fabrica.model.vos.Tamanio;
import fiuba.td.fabrica.model.xml.lineaproduccion.LineasProduccion;
import fiuba.td.fabrica.model.xml.lineaproduccion.LineasProduccionValidationEventHandler;
import fiuba.td.fabrica.model.xml.lineaproduccion.LineasProduccion.LineaProduccion;
import fiuba.td.fabrica.model.xml.maquina.Maquinas;
import fiuba.td.fabrica.model.xml.maquina.MaquinasValidationEventHandler;
import fiuba.td.fabrica.model.xml.maquina.Maquinas.Maquina;
import fiuba.td.fabrica.model.xml.terreno.Terrenos;
import fiuba.td.fabrica.model.xml.terreno.TerrenosValidationEventHandler;
import fiuba.td.fabrica.model.xml.terreno.Terrenos.Terreno;


public class XmlUtils {
	private static String PAQUETE_XML = "fiuba.td.fabrica.model.xml";
	private static String DIRECTORIO_XML = System.getProperty("user.dir") + "\\xml\\";
	private static String DIRECTORIO_IMG = System.getProperty("user.dir") + "\\recursos\\";
	
	static Logger logger = Logger.getLogger(XmlUtils.class);
	
	/**
	 * Se lee del xml de maquinas y se levanta a una lista de maquinas 
	 * @return lista de maquinas disponibles
	 */
	public static List<fiuba.td.fabrica.model.entities.Maquina> getMaquinasFromXml() {
		List<fiuba.td.fabrica.model.entities.Maquina> maquinas = new ArrayList<fiuba.td.fabrica.model.entities.Maquina>();
		
		try {
			JAXBContext jaxbContext = JAXBContext.newInstance (PAQUETE_XML + ".maquina");
			Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
			unmarshaller.setEventHandler(new MaquinasValidationEventHandler());

			Maquinas maquinasXml = (Maquinas)unmarshaller.unmarshal(new File(DIRECTORIO_XML + "maquinas.xml"));

			for (Maquina maquinaXml : maquinasXml.getMaquina()){
				try {
					fiuba.td.fabrica.model.entities.Maquina maquina = MaquinaFactory.getInstance().createMaquinaReal(maquinaXml.getTipo(), 
																									maquinaXml.getNombre(), 
																									maquinaXml.getCosto().doubleValue(), 
																									maquinaXml.getTamanio().getLargo(), 
																									maquinaXml.getTamanio().getAncho());
					maquinas.add(maquina);
				} catch (TipoMaquinaInvalidoException e) {
					e.printStackTrace();
				}
			}

		} catch (JAXBException e) {
			e.printStackTrace();
		}
		
		return maquinas;
	}

	/**
	 * Se lee del xml de terrenos y se levanta a una lista de terrenos 
	 * @return lista de terrenos disponibles
	 */
	public static List<fiuba.td.fabrica.model.entities.Terreno> getTerrenosFromXml() {
		List<fiuba.td.fabrica.model.entities.Terreno> terrenos = new ArrayList<fiuba.td.fabrica.model.entities.Terreno>();
		
		try {
			JAXBContext jaxbContext = JAXBContext.newInstance (PAQUETE_XML + ".terreno");
			Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
			unmarshaller.setEventHandler(new TerrenosValidationEventHandler());
			
			Terrenos terrenosXml = (Terrenos)unmarshaller.unmarshal(new File(DIRECTORIO_XML + "terrenos.xml"));
			
			for (Terreno terrenoXml : terrenosXml.getTerreno()){
				fiuba.td.fabrica.model.entities.Terreno terreno = new fiuba.td.fabrica.model.entities.Terreno(
						terrenoXml.getNombre(), 
						new Tamanio (terrenoXml.getTamanio().getLargo(), terrenoXml.getTamanio().getAncho()), 
						terrenoXml.getPrecio().getVenta().doubleValue(), 
						terrenoXml.getPrecio().getAlquiler().doubleValue(),
						DIRECTORIO_IMG + terrenoXml.getImagen());
				
				terrenos.add(terreno);
			}
			
		} catch (JAXBException e) {
			e.printStackTrace();
		}
		
		return terrenos;
	}

	/**
	 * Si no se le pasa un xml, se usa el default
	 * @return
	 */
	public static List<fiuba.td.fabrica.model.beans.LineaProduccionBean> getLineasProduccionBeanFromXml() {
		return getLineasProduccionBeanFromXml("lineas_produccion");
	}
	
	/**
	 * Se lee del xml de lineas de produccion y se levanta a una lista de lineas 
	 * @return lista de lineas disponibles y no disponibles
	 */
	public static List<fiuba.td.fabrica.model.beans.LineaProduccionBean> getLineasProduccionBeanFromXml(String xmlFileName) {
		List<fiuba.td.fabrica.model.beans.LineaProduccionBean> lineasProduccion = new ArrayList<fiuba.td.fabrica.model.beans.LineaProduccionBean>();
		
		try {
			JAXBContext jaxbContext = JAXBContext.newInstance (PAQUETE_XML + ".lineaproduccion");
			Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
			unmarshaller.setEventHandler(new LineasProduccionValidationEventHandler());

			LineasProduccion lineasProduccionXml = (LineasProduccion)unmarshaller.unmarshal(new File(DIRECTORIO_XML + xmlFileName + ".xml"));

			for (LineaProduccion lineaProduccionXml : lineasProduccionXml.getLineaProduccion()){
				// Obtengo el producto que fabrica la linea
				Producto producto = new fiuba.td.fabrica.model.entities.Producto (
														lineaProduccionXml.getProducto().getNombre(),
														lineaProduccionXml.getProducto().getCosto().doubleValue(),
														lineaProduccionXml.getProducto().getPrecioReal().doubleValue());
				
				// Creo el bean
				fiuba.td.fabrica.model.beans.LineaProduccionBean lineaProduccion = 
					new fiuba.td.fabrica.model.beans.LineaProduccionBean (producto, lineaProduccionXml.getCostoInversion().doubleValue());

				
				// Obtengo las maquinas y se las seteo a la linea
				for (fiuba.td.fabrica.model.xml.lineaproduccion.LineasProduccion.LineaProduccion.Maquinas.Maquina maquinaXml : lineaProduccionXml.getMaquinas().getMaquina()){
					fiuba.td.fabrica.model.entities.Maquina maquina = null;
					try {
						maquina = MaquinaFactory.getInstance().createMaquinaLineaProduccion(maquinaXml.getTipo(), maquinaXml.getNombre());
						lineaProduccion.addMaquina(maquina);
					} catch (TipoMaquinaInvalidoException e) {
						e.printStackTrace();
					}
				}

				// Seteo la maquina inicial a la linea de produccion
				if (lineaProduccion.getMaquinas() != null && !lineaProduccion.getMaquinas().isEmpty()){
					lineaProduccion.setMaquinaInicial(lineaProduccion.getMaquinas().get(0));
				}
				
				// Conecto las maquinas con cintas transportadoras y las agrego a los elementos de la fabrica
				for (int i = 0; i < (lineaProduccion.getMaquinas().size() - 1); i++){
					CintaTransportadora cintaTransportadora = new CintaTransportadora(1);
					try {
						lineaProduccion.addCintaTransportadora( cintaTransportadora, 
																lineaProduccion.getMaquinas().get(i), 
																lineaProduccion.getMaquinas().get(i+1));
					} catch (ConexionCintaTransportadoraOcupadaException e) {
						e.printStackTrace();
					} catch (ConexionConectableOcupadoException e) {
						e.printStackTrace();
					}
					
					lineaProduccion.getElementosFabrica().add(lineaProduccion.getMaquinas().get(i));
					lineaProduccion.getElementosFabrica().add(cintaTransportadora);
				}
				
				lineasProduccion.add(lineaProduccion);
			}

		} catch (JAXBException e) {
			e.printStackTrace();
		}
		
		return lineasProduccion;
	}
	
}
